#include <linux/module.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <asm/uaccess.h>  
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/list_sort.h>
#include <linux/seq_file.h>
#define CMD_L_LENGTH 1000
static char CMD_L[CMD_L_LENGTH];
struct list_p
{
       char comm[100];
        int pid;
        struct list_head list;
};

struct list_p *main_l=NULL;

struct list_head *my_seq_start(struct list_head *paramhead,
                                         loff_t *pos)
{        
       if (*pos!=0)
{return NULL;}
else return main_l->list.next;
}

static void *my_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
        struct list_head *tmp=NULL;
     
                tmp=v;          
                tmp=tmp->next;                
     if (tmp == &main_l->list)
{return NULL;}
        return tmp;        
}
        

static int my_seq_show(struct seq_file *s, void *v)
{
       struct list_p *head1 = v;
struct list_p *val= list_entry (head1, struct list_p, list);

         seq_printf (s, "<%d>: %s\n", val->pid, val->comm);

return 0;
}

static void my_seq_stop(struct seq_file *s, void *v)
        {
                
        }
static const struct seq_operations my_seq_ops = {
                .start = my_seq_start,
                .next  = my_seq_next,
                .stop  = my_seq_stop,
                .show  = my_seq_show
};
int strai(void *, struct list_head*, struct list_head*);

int revers(void *, struct list_head *, struct list_head *);

int ab(void *, struct list_head *, struct list_head *);

int zx(void *, struct list_head *, struct list_head *);

int build_list()
{      
        struct list_p *tail;
        struct task_struct *task_list;
        struct list_head *p;
        main_l=(struct list_p*)kmalloc(sizeof(struct list_p), GFP_KERNEL);
        INIT_LIST_HEAD(&(main_l->list));
                for_each_process(task_list)
              {               
                
                tail=(struct list_p*)kmalloc(sizeof(struct list_p), GFP_KERNEL);
                tail->pid=task_list->pid;
                strcpy(tail->comm,task_list->comm);
                list_add_tail(&(tail->list), &(main_l->list));                
        }      
        
        return 0;}

void clean_list(void)
{
        struct list_head *p, *q;
        struct list_p *tmp = NULL;
        list_for_each_safe(p, q, &main_l->list)
        {
                tmp = list_entry(p, struct list_p, list);
                list_del(p);
                kfree (tmp);
        }
}

static int my_open(struct inode *inode, struct  file *file)
{
        seq_open(file, &my_seq_ops);
        return 0;
}

static int my_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
        int i;
        struct list_p *tmp;
        struct list_head *p;
        for (i = 0; i < CMD_L_LENGTH - 1 && i < len; i++)
                get_user(CMD_L[i], buff + i);
        CMD_L[i] = '\0';
        if(!(strcmp(CMD_L,"refresh\n")))
        {
        clean_list();
                build_list();

        }
        if(!(strcmp(CMD_L,"straight\n")))
        {
 clean_list();
                build_list();
                list_sort(0, &(main_l->list), strai);
                list_for_each(p, &main_l->list)
                {
                        tmp = list_entry (p, struct list_p, list);
                       
                }
        }
        if(!(strcmp(CMD_L,"reverse\n")))
        {
 clean_list();
                build_list();
                list_sort(0, &(main_l->list), revers);
                list_for_each(p, &main_l->list)
                {
                        tmp = list_entry (p, struct list_p, list);
                        
                }
        }
        if(!(strcmp(CMD_L,"abc\n")))
        {
                build_list();
                list_sort(0, &(main_l->list), ab);
                list_for_each(p, &main_l->list)
                {
                        tmp = list_entry (p, struct list_p, list);
                        
                }
        }
        if(!(strcmp(CMD_L,"zyx\n")))
        {
 clean_list();
                build_list();
                list_sort(0, &(main_l->list), zx);
        }       
        return i;
}
static struct file_operations myhandlers={
        .owner = THIS_MODULE,   
        .read=seq_read,
        .open=my_open,
        .write=my_write        
};

int strai(void * priv, struct list_head *a, struct list_head *b)
{       
        struct list_p *fir = NULL;
        struct list_p *sec = NULL;
        fir=list_entry (a, struct list_p, list);
        sec=list_entry (b, struct list_p, list);
return fir->pid-sec->pid;
}
int revers(void * priv, struct list_head *a, struct list_head *b)
{       
        struct list_p *fir = NULL;
        struct list_p *sec = NULL;
        fir=list_entry (a, struct list_p, list);
        sec=list_entry (b, struct list_p, list);

      return sec->pid-fir->pid;
}
int ab(void * priv, struct list_head *a, struct list_head *b)
{        
        struct list_p *fir = NULL;
        struct list_p *sec = NULL;
        fir=list_entry (a, struct list_p, list);
        sec=list_entry (b, struct list_p, list);
        return strcmp(fir->comm, sec->comm);
        
}
int zx(void * priv, struct list_head *a, struct list_head *b)
{       
        int i=0;        
        struct list_p *fir = NULL;
        struct list_p *sec = NULL;
        fir=list_entry (a, struct list_p, list);
        sec=list_entry (b, struct list_p, list);

        i=strcmp(fir->comm, sec->comm);
        return (-1)*i;        
}

static int  task_init()
{
        proc_create("snapshot", 0, NULL, &myhandlers);
        build_list();
        return 0;
}


static void task_exit()
{
         clean_list();
        remove_proc_entry("snapshot", 0);
}

module_init (task_init);
module_exit (task_exit);
